#include "BaseVector.h"
#include<cmath>
#include"Matrix.h"

BaseVector::BaseVector(int n, double* values)
{
	this->n = n;
	this->data = new double[n];
	if (values != nullptr)
	{
		this->SetValues(values);
	}
}

BaseVector::BaseVector(const BaseVector & v)
{
	this->n = v.n;
	this->data = new double[n];
	double *values = v.GetValues();
	this->SetValues(values);
	delete []values;
}


BaseVector::~BaseVector()
{
	delete[]data;
	//data = nullptr;
}

void BaseVector::SetUpOrthogonalBasisByW(BaseVector & u, BaseVector & v, BaseVector & w)
{
	w = Identity(w);
	double *n = w.GetValues();
	int min = 0;
	for (int i = 1; i < w.n; i++)
		if (n[min] > n[i])
			min = i;
	n[min] = 1;
	BaseVector t(w.n, n);
	if (t == w)
	{
		n[min] = 2;
		t = BaseVector(w.n, n);
	}
	u = Identity(CrossProduct(t, w));
	v = CrossProduct(w, u);
	delete[]n;
}

double BaseVector::DotProduct(BaseVector v1, BaseVector v2)
{
	double res = 0;
	for (int i = 0; i < v1.n-1; i++)
	{
		res += v1.data[i] * v2.data[i];
	}
	return res;
}

BaseVector BaseVector::CrossProduct(BaseVector v1, BaseVector v2)
{
	double res[4] = {};
	if (v1.n == 3)
	{
		res[0] = 0;
		res[1] = 0;
		res[2] = v1.data[0] * v2.data[1] - v1.data[1] * v2.data[0];
		res[3] = 0;
	}
	else if (v1.n == 4)
	{
		res[0] = v1.data[1] * v2.data[2] - v1.data[2] * v2.data[1];
		res[1] = v1.data[2] * v2.data[0] - v1.data[0] * v2.data[2];
		res[2] = v1.data[0] * v2.data[1] - v1.data[1] * v2.data[0];
		res[3] = 0;
	}
	return BaseVector(4, res);
}

BaseVector BaseVector::Identity(BaseVector v)
{
	return v / Norm(v);
}

double BaseVector::Norm(BaseVector v)
{
	double res = 0;
	for (int i = 0; i < v.n - 1; i++)
	{
		res += (v.data[i] * v.data[i]);
	}
	return sqrt(res);
}

Matrix BaseVector::ToMatrix(BaseVector v)
{
	double *values = v.GetValues();
	Matrix res(v.n, 1, values);
	delete[] values;
	return res;
}

BaseVector BaseVector::FromMatrix(Matrix mat)
{
	double *values = mat.GetValues();
	BaseVector res(mat.m, values);
	delete[]values;
	return res;
}

BaseVector BaseVector::Homogenize(BaseVector v)
{
	return v / v.data[v.n - 1];
}

void BaseVector::SetValues(double data[])
{
	for (int i = 0; i < n; i++)
	{
		this->data[i] = data[i];
	}
}

double * BaseVector::GetValues() const
{
	double* result = new double[n];
	for (int i = 0; i < n; i++)
	{
		result[i] = data[i];
	}
	return result;
}

Matrix BaseVector::ToMatrix()
{
	return ToMatrix(*this);
}

void BaseVector::Identity()
{
	*this = Identity(*this);
}

double BaseVector::MinValue(int & index)
{
	double minV = this->data[0];
	index = 0;
	for (int i = 1; i < n - 1; i++)
	{
		if (this->data[i] < minV)
		{
			minV = this->data[i];
			index = i;
		}
	}
	return minV;
}

double BaseVector::MaxValue(int & index)
{
	double maxV = this->data[0];
	index = 0;
	for (int i = 1; i < n - 1; i++)
	{
		if (this->data[i] > maxV)
		{
			maxV = this->data[i];
			index = i;
		}
	}
	return maxV;
}

void BaseVector::Homogenize()
{
	for (int i = 0; i < n; i++)
	{
		this->data[i] /= this->data[n - 1];
	}
}

BaseVector BaseVector::operator=(BaseVector v)
{
	if (this == &v)return *this;
	double *values = v.GetValues();
	this->SetValues(values);
	delete values;
	return *this;
}

BaseVector BaseVector::operator+=(BaseVector v)
{
	for (int i = 0; i < this->n - 1; i++)
	{
		this->data[i] += v.data[i];
	}
	return (*this);
}

BaseVector operator/(BaseVector v, double k)
{
	for (int i = 0; i < v.n; i++)
	{
		v.data[i] /= k;
	}
	return v;
}

BaseVector operator/=(BaseVector& v, double k)
{
	for (int i = 0; i < v.n; i++)
	{
		v.data[i] /= k;
	}
	return v;
}

BaseVector operator*(BaseVector v, double k)
{
	for (int i = 0; i < v.n; i++)
	{
		v.data[i] *= k;
	}
	return v;
}

BaseVector operator*(double k, BaseVector v)
{
	return v * k;
}

bool operator==(BaseVector v1, BaseVector v2)
{
	for (int i = 0; i < v1.n; i++)
	{
		if (fabs(v1.data[i] - v2.data[i]) > 1e-5)
		{
			return false;
		}
	}
	return true;
}

bool operator!=(BaseVector v1, BaseVector v2)
{
	for (int i = 0; i < v1.n; i++)
	{
		if (fabs(v1.data[i] - v2.data[i]) > 1e-5)
		{
			return true;
		}
	}
	return false;
}

BaseVector operator-(BaseVector v)
{
	for (int i = 0; i < v.n; i++)
	{
		v.data[i] *= -1;
	}
	return v;
}

BaseVector operator-(BaseVector v1, BaseVector v2)
{
	for (int i = 0; i < v1.n; i++)
	{
		v1.data[i] -= v2.data[i];
	}
	return v1;
}

BaseVector operator+(BaseVector v1, BaseVector v2)
{
	for (int i = 0; i < v1.n; i++)
	{
		v1.data[i] += v2.data[i];
	}
	return v1;
}

BaseVector operator/(BaseVector v1, BaseVector v2)
{
	for (int i = 0; i < v1.n - 1; i++)
	{
		v1.data[i] /= v2.data[i];
	}
	return v1;
}

BaseVector operator*(BaseVector v1, BaseVector v2)
{
	for (int i = 0; i < v1.n - 1; i++)
	{
		v1.data[i] *= v2.data[i];
	}
	return v1;
}
